
/*
    渲染
        渲染主体
            渲染头部
            渲染一周
            渲染矩阵
                今天
                非本月
    绑定事件
        选中日期
        切换月份
*/

interface ClanderInterface {
    eml: HTMLElement
    name: string

    renderHeader() : void
    renderMatrix() : void
    bindEvent(): void
    choiceDate(str: any): string
}

const formatNumber = (num: (number|string)) => {
    num = parseInt(num + '', 10);
    return num < 10 ? `0${num}` : num
}

const createDiv = (
    className: string,
    tagName: string = 'div',
    innerHTML?: (HTMLElement [] | string | number)
) => {
    let eml = document.createElement(tagName)
    eml.className = className
    if (typeof innerHTML === 'string' || typeof innerHTML === 'number') {
        eml.innerHTML = innerHTML + ''
    } else if (Array.isArray(innerHTML)) {
        innerHTML.forEach(itemEml => {
            eml.appendChild(itemEml)
        })
    }
    return eml
}

const formatDate = (data: Date) => {
    let str = `${
        data.getFullYear()
    }-${
        formatNumber(data.getMonth() + 1)
    }-${
        formatNumber(data.getDate())
    }`
    return str
}

const renderWeek = () => {
    let weaks = ['一', '二', '三', '四', '五', '六', '日']
    return createDiv(
        'center-caption', 
        'div', 
        weaks.map(str => {
            return createDiv('center-caption__coll', "div", str)
        })
    )
}

class Clander implements ClanderInterface{
    public eml: HTMLInputElement;
    public name: string = ''

    private currentData: Date = new Date
    private isRender: Boolean = false

    // 头部
    private prve: HTMLElement = createDiv('box-header__lt', 'div', '<')
    private next: HTMLElement = createDiv('box-header__gt', 'div', '>')
    private currentDataEml: HTMLElement = createDiv('box-header__data')
    private header: HTMLElement = createDiv('box-header', 'div', [
        this.prve,
        this.currentDataEml,
        this.next
    ])

    private matrix: HTMLElement = createDiv('center-list')
    private box: HTMLElement = createDiv('box', 'div', [
        this.header,
        this.matrix
    ])

    static instance: Clander[] = []
    
    constructor(eml: HTMLInputElement, name: string) {
        this.eml = eml
        this.name = name
        this.eml.value = name
        this.run()
        Clander.instance.push(this)
    }

    run() {
        // 渲染
        const { top, left } = this.eml.getBoundingClientRect()
        this.box.style.top = `${top + this.eml.offsetHeight + 10}px`
        this.box.style.left = `${left}px`
        // 事件绑定
        this.bindEvent()
    }
    // 每次修改月份， 重新渲染
    renderBody () {
        this.isRender = true
        this.renderHeader()
        this.renderMatrix()
        document.body.appendChild(this.box)
    }
    renderHeader() {
        this.currentDataEml.innerHTML = formatDate(this.currentData)
    }
    // 渲染矩阵
    renderMatrix() {
        this.matrix.innerHTML = ''
        this.matrix.appendChild(renderWeek())
        let table = createDiv('center-table')
        this.matrix.appendChild(table)

        let firstDate = new Date(
            this.currentData.getFullYear(),
            this.currentData.getMonth(),
            1,
        )
        firstDate.setDate(-firstDate.getDay() + 2)
        for (let i = 0; i < 42; i++) {

            let className = 'center-caption__coll'
            // 是当天
            if (formatDate(firstDate) === formatDate(this.currentData)) {
                className = 'center-caption__coll center-caption__coll__active'
            } else if (firstDate.getMonth() !== this.currentData.getMonth()) {
                // 是本月
                className = 'center-caption__coll center-caption__coll__dark'
            }
            let tempDate = createDiv(
                className,
                'div',
                formatNumber(firstDate.getDate())
            )
            tempDate.dataset.value = formatDate(firstDate)
            table.appendChild(tempDate)

            tempDate.addEventListener('click', (e) => {
                let target = e.target as HTMLElement
                this.choiceDate(target.dataset.value)
                this.destroy()
                e.stopPropagation()
            })
            firstDate.setDate(firstDate.getDate() + 1)
        }

    }
    bindEvent() {
        this.prve.addEventListener('click', (e) => {
            this.currentData.setMonth(this.currentData.getMonth() - 1)
            this.renderBody()
            e.stopPropagation()
        })
        this.next.addEventListener('click', (e) => {
            this.currentData.setMonth(this.currentData.getMonth() + 1)
            this.renderBody()
            e.stopPropagation()
        })
        this.eml.addEventListener('focus', () => {
            this.renderBody()
        })
        // 点击文本框，销毁其他的日期控件
        this.eml.addEventListener('click', () => {
            for (let t of Clander.instance) {
                if (t.name !== this.name) {
                    t.destroy()
                }
            }
        })

        this.box.addEventListener('click', (e) => {
            e.stopPropagation()
        })
        this.eml.addEventListener('click', (e) => {
            e.stopPropagation()
        })
        document.addEventListener('click', ()=> {
            this.destroy()
        })
    }

    destroy() {
        if (this.isRender === true) {
            document.body.removeChild(this.box)
            this.isRender = false
        }
    }

    choiceDate(str: any) {
        this.eml.value = str
        return str
    }
}

export default Clander
